#include "StdAfx.h"
#include "UIEnv.h"
#include "Enviroment.h"
#include "ImeWindowForCegui.h"
#include "../Win32IMESensor/Win32ImeSensor.h"

#define GUISTYLENAME "TaharezLook" /*"WindowsLook"*/
#define GUISTYLEFILE "TaharezLook.scheme" /*"WindowsLook.scheme"*/
#define GUIIMGSETNAME "TaharezLook" /*"WindowsLook"*/
#define LAYOUT_FRAMEWIDTH 600
#define LAYOUT_FRAMEHEIGHT 400
#define LAYOUT_MARGIN 5
#define LAYOUT_INPUTBOXHEIGHT 30
#define USESYSTEMMOUSECURSOR true

IMPLEMENT_Singleton(VWD::UIEnv);

CEGUI::FrameWindow *ConsoleWindow=0;
CEGUI::MultiLineEditbox *ConsoleWindow_MultiLineEditbox=0;
CEGUI::Editbox *ConsoleWindow_Editbox=0;
VWD::ImeWindowForCegui * imeWindow = 0;

void Console_OnRequestWriteLine(const std::string& msg);

const CEGUI::Window* GetFocusedControl()
{
	CEGUI::WindowManager::WindowIterator wit = CEGUI::WindowManager::getSingleton().getIterator();

	while(!wit.isAtEnd())
	{
		const CEGUI::Window* widget = (*wit)->getActiveChild();
		if(widget)
		{
			return widget;
		}
		wit++;
	}

	return 0;
}

class WndEvtListener : public Ogre::WindowEventListener
{
public:
	void windowResized(Ogre::RenderWindow* rw)
	{
		CEGUI::System::getSingleton().notifyDisplaySizeChanged(
			CEGUI::Size(static_cast<float>(rw->getWidth()),
			static_cast<float>(rw->getHeight())));
	}
};

VWD::UIEnv::UIEnv(void)
{
	
}
VWD::UIEnv::~UIEnv(void)
{

}

// void Enviroment_OnUserPressCtrlC()
// {
// 
// }
// 
// void Enviroment_OnUserPressCtrlX()
// {
// 
// }
// 
// void Enviroment_OnUserPressCtrlV()
// {
// 	CEGUI::Window* widget = GetFocusedControl();
// 	CEGUI::Editbox* editbox = dynamic_cast<CEGUI::Editbox*>(widget);
// 	if(editbox!=0)
// 	{
// 		editbox->insertText(,)
// 	}
// }

bool ConsoleWindow_OnCloseClicked(const CEGUI::EventArgs& e)
{
	CA::Console::Hide();
	return true;
}

// CEGUI::String encode(const char * c)
// {
// 	static CEGUI::String str;
// 	WCHAR e;
// 	str.clear();
// 	int i = 0;
// 	while(c[i])
// 	{
// 		if(unsigned char(c[i])>=161)
// 		{ 
// 			MultiByteToWideChar(0,0,c+i,2,&e,1);
// 			str.append(1,e);
// 			i+=2;
// 		} 
// 		else
// 		{
// 			str.append(1,c[i]);
// 			i++;
// 		}
// 	}
// 	return str;
// }

// std::string& decode(const CEGUI::String& str)
// {
// 	char sdes[2048];	
// 	static std::string result;
// 	int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);	
// 	wchar_t* wcstr = new wchar_t[len];	
// 	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wcstr, len);	
// 	int wlen = WideCharToMultiByte(CP_ACP, 0, wcstr, -1, NULL, 0, NULL, NULL);	
// 	char* nstr = new char[wlen];	
// 	WideCharToMultiByte(CP_ACP, 0, wcstr, -1, nstr, wlen, NULL, NULL);	
// 	strcpy(sdes, nstr);	
// 	delete[] wcstr;	
// 	delete[] nstr;	
// 	result = sdes;	
// 	return result;
// }

// std::string decode(const CEGUI::String& str)
// {
// 	const char* chTemp = str.c_str();
// 	WCHAR*     strA;      
// 
// 	int i= MultiByteToWideChar(CP_UTF8,0 ,(char*)chTemp,-1,NULL,0); 
// 	strA = new WCHAR[i];       
// 	MultiByteToWideChar(CP_UTF8,0,(char*)chTemp,-1,strA,i);   
// 
// 	i= WideCharToMultiByte(CP_ACP,0,strA,-1,NULL,0,NULL,NULL);
// 	char *strB = new char[i];
// 	WideCharToMultiByte (CP_ACP,0,strA,-1,strB,i,NULL,NULL);
// 
// 	std::string strReturn = std::string(strB);
// 	delete strA;
// 	delete strB;
// 
// 	return strReturn;
// }

std::string CheckForshot(const std::string& cmd)
{
	std::string str = cmd;
	boost::trim(str);

	if(str=="cls") return "Console.Cls()";

	if(str=="shutdown") return "Console.Shutdown()";

	if(str=="hide") return "Console.Hide()";

	return cmd;
}

CEGUI::String _lastAcceptedConsoleCommand;

bool ConsoleWindowEditbox_OnTextAccepted(const CEGUI::EventArgs& e)
{
	using namespace CEGUI;
	
	_lastAcceptedConsoleCommand = ConsoleWindow_Editbox->getText();
	if(_lastAcceptedConsoleCommand.empty())return false;
	//std::string utf8str = decode(txt);
	std::string utf8str =  CheckForshot(ScriptBackend::UIUtility::toStdString(_lastAcceptedConsoleCommand));

	Console_OnRequestWriteLine(utf8str);
	CA::Console::Eval(utf8str);
	ConsoleWindow_Editbox->setText("");
	return true;
}

bool ConsoleWindowEditbox_OnKeyDown(const CEGUI::EventArgs& _e)
{
	using namespace CEGUI;
	const KeyEventArgs& e=(const KeyEventArgs&)_e;
	if(e.scancode==Key::ArrowUp)
	{
		ConsoleWindow_Editbox->setText(_lastAcceptedConsoleCommand);
		return true;
	}
	return false;
}

HCURSOR currentCursor = LoadCursor(NULL,IDC_ARROW);

bool MouseCursor_OnImageChanged(const CEGUI::EventArgs& e)
{
	if(!(USESYSTEMMOUSECURSOR))return false;

	static CEGUI::String MouseArrow = "MouseArrow";
	static HCURSOR arrow = LoadCursor(NULL,IDC_ARROW);
	static CEGUI::String MouseTextBar = "MouseTextBar";
	static HCURSOR txt = LoadCursor(NULL,IDC_IBEAM);
	static CEGUI::String MouseNoSoCursor = "MouseNoSoCursor";
	static HCURSOR noso = LoadCursor(NULL,IDC_SIZENS);
	static CEGUI::String MouseMoveCursor = "MouseMoveCursor";
	static HCURSOR move = LoadCursor(NULL,IDC_SIZEALL);
	static CEGUI::String MouseTarget = "MouseTarget";
	static HCURSOR tgt = LoadCursor(NULL,IDC_HAND);
	static CEGUI::String MouseEsWeCursor = "MouseEsWeCursor";
	static HCURSOR eswe = LoadCursor(NULL,IDC_SIZEWE);
	static CEGUI::String MouseNeSwCursor = "MouseNeSwCursor";
	static HCURSOR nesw = LoadCursor(NULL,IDC_SIZENESW);
	static CEGUI::String MouseNwSeCursor = "MouseNwSeCursor";
	static HCURSOR nwse = LoadCursor(NULL,IDC_SIZENWSE);

	const CEGUI::MouseCursorEventArgs& me = (const CEGUI::MouseCursorEventArgs&)e;
	
	if(me.image!=0)	
	{	
		CEGUI::String cursorname = me.image->getName();
		
		if(cursorname==MouseArrow) currentCursor=arrow;
		else if(cursorname==MouseTextBar) currentCursor=txt;
		else if(cursorname==MouseNoSoCursor) currentCursor=noso;
		else if(cursorname==MouseMoveCursor) currentCursor=move;
		else if(cursorname==MouseTarget) currentCursor=tgt;
		else if(cursorname==MouseEsWeCursor) currentCursor=eswe;
		else if(cursorname==MouseNeSwCursor) currentCursor=nesw;
		else if(cursorname==MouseNwSeCursor) currentCursor=nwse;
	}
	else
	{
		currentCursor = arrow;
	}
	
	return false;
}

void Console_OnRequestInit()
{
	using namespace CEGUI;

	WindowManager &mgr = WindowManager::getSingleton();	
	ConsoleWindow = (FrameWindow*)mgr.createWindow(GUISTYLENAME"/FrameWindow","Console");	
	ConsoleWindow->getTitlebar()->setText("Console");		
	ConsoleWindow->setWidth(UDim(0,LAYOUT_FRAMEWIDTH));
	ConsoleWindow->setHeight(UDim(0,LAYOUT_FRAMEHEIGHT));	
	ConsoleWindow->setHorizontalAlignment(HA_CENTRE);
	ConsoleWindow->setVerticalAlignment(VA_CENTRE);	
	ConsoleWindow->setAlwaysOnTop(true);
	ConsoleWindow->setSizingEnabled(false);
	
	float titlebarHeight = ConsoleWindow->getTitlebar()->getPixelSize().d_height;

	ConsoleWindow_Editbox = (Editbox*)mgr.createWindow(GUISTYLENAME"/Editbox","Console/Editbox");
	ConsoleWindow_Editbox->setHeight(UDim(0,LAYOUT_INPUTBOXHEIGHT));
	ConsoleWindow_Editbox->setWidth(UDim(0.98,0));//LAYOUT_FRAMEWIDTH-LAYOUT_MARGIN*2));
	ConsoleWindow_Editbox->setHorizontalAlignment(HA_CENTRE);
	//ConsoleWindow_Editbox->setXPosition(UDim(0,LAYOUT_MARGIN));
	ConsoleWindow_Editbox->setYPosition(UDim(0,LAYOUT_FRAMEHEIGHT-titlebarHeight-LAYOUT_INPUTBOXHEIGHT-LAYOUT_MARGIN));

	ConsoleWindow_MultiLineEditbox = (MultiLineEditbox*)mgr.createWindow(GUISTYLENAME"/MultiLineEditbox","Console/MultiLineEditbox");
	//ConsoleWindow_MultiLineEditbox->setXPosition(UDim(0,LAYOUT_MARGIN));
	ConsoleWindow_MultiLineEditbox->setHorizontalAlignment(HA_CENTRE);
	ConsoleWindow_MultiLineEditbox->setYPosition(UDim(0,LAYOUT_MARGIN));
	ConsoleWindow_MultiLineEditbox->setWidth(UDim(0.98,0));//LAYOUT_FRAMEWIDTH-LAYOUT_MARGIN*2));
	ConsoleWindow_MultiLineEditbox->setHeight(UDim(0,LAYOUT_FRAMEHEIGHT-titlebarHeight-LAYOUT_INPUTBOXHEIGHT-LAYOUT_MARGIN*3));	
	ConsoleWindow_MultiLineEditbox->setReadOnly(true);


	ConsoleWindow->addChildWindow(ConsoleWindow_MultiLineEditbox);
	ConsoleWindow->addChildWindow(ConsoleWindow_Editbox);


	ConsoleWindow->subscribeEvent(FrameWindow::EventCloseClicked,Event::Subscriber(&ConsoleWindow_OnCloseClicked));	
	ConsoleWindow_Editbox->subscribeEvent(Editbox::EventTextAccepted,Event::Subscriber(&ConsoleWindowEditbox_OnTextAccepted));
	ConsoleWindow_Editbox->subscribeEvent(Window::EventKeyDown,Event::Subscriber(&ConsoleWindowEditbox_OnKeyDown));
	System::getSingleton().getGUISheet()->addChildWindow(ConsoleWindow);

	ConsoleWindow_Editbox->activate();
	
	if(USESYSTEMMOUSECURSOR)
		MouseCursor::getSingleton().subscribeEvent(MouseCursor::EventImageChanged,Event::Subscriber(&MouseCursor_OnImageChanged));
	
}
void Console_OnRequestShow()
{
	ConsoleWindow->setVisible(true);
}
void Console_OnRequestCls()
{	
	ConsoleWindow_MultiLineEditbox->setText("");
}
void Console_OnRequestHide()
{
	ConsoleWindow->setVisible(false);
}
void Console_OnRequestShutdown()
{
	VWD::UIEnv::getInstancePtr()->OnRequestShutdown();
}
void Console_OnRequestWriteLine(const std::string& msg) 
{
	//CEGUI::String displayed = encode(msg.c_str());		
	CEGUI::String displayed = ScriptBackend::UIUtility::toCeguiString(msg);	

	ConsoleWindow_MultiLineEditbox->appendText(displayed);
	CEGUI::Scrollbar *vertScrollbar = ConsoleWindow_MultiLineEditbox->getVertScrollbar();
	vertScrollbar->setScrollPosition(vertScrollbar->getDocumentSize()-vertScrollbar->getPageSize());
}

CEGUI::OgreRenderer *renderer=0;

void VWD::UIEnv::Init()
{
// 	renderer = new CEGUI::OgreCEGUIRenderer(
// 		VWD::Enviroment::RenderWindow		
// 		,Ogre::RENDER_QUEUE_OVERLAY
// 		,true
// 		,3000
// 		,VWD::Enviroment::SceneManager
// 		);
// 
// 	if(VWD::Enviroment::luaState==0)
// 	{
// 		scriptModule = new CEGUI::LuaScriptModule();
// 		VWD::Enviroment::luaState = scriptModule->getLuaState();
// 	}
// 	else
// 	{
// 		scriptModule = new CEGUI::LuaScriptModule(VWD::Enviroment::luaState);
// 	}
// 	ceguisystem = new CEGUI::System(renderer,0,0,scriptModule,"cegui.config.xml");
	
// 	CEGUI::SchemeManager::getSingletonPtr()->loadScheme("QuadraticLook.scheme");
// 	CEGUI::Window* window = CEGUI::WindowManager::getSingletonPtr()->loadWindowLayout("VWDMain.layout");
// 	ceguisystem->setGUISheet(window);
// 	window->show();
	
	
#if _WIN32
	//ShowCursor(FALSE);
#endif

	{
		using namespace CEGUI;
		renderer = &OgreRenderer::bootstrapSystem(*Enviroment::RenderWindow);

		Ogre::WindowEventUtilities::addWindowEventListener(Enviroment::RenderWindow,new WndEvtListener());		

//		System::create(renderer);
		WindowManager &wmg = WindowManager::getSingleton();
		Window* guiRoot = wmg.createWindow("DefaultWindow", "root" );
		System::getSingleton().setGUISheet( guiRoot );
		guiRoot->show();
		
		
		SchemeManager::getSingleton().create(GUISTYLEFILE);
 		System::getSingleton().setDefaultMouseCursor(GUIIMGSETNAME, "MouseArrow");	
		if(USESYSTEMMOUSECURSOR)
		{
			MouseCursor::getSingleton().hide();		
		}
		else
		{
			ShowCursor(FALSE);
			MouseCursor::getSingleton().show();		
		}
	}

	{
		using namespace CA;
		Console::OnRequestHide.connect(&Console_OnRequestHide);
		Console::OnRequestInit.connect(&Console_OnRequestInit);
		Console::OnRequestShow.connect(&Console_OnRequestShow);
		Console::OnRequestShutdown.connect(&Console_OnRequestShutdown);
		Console::OnRequestWriteLine.connect(&Console_OnRequestWriteLine);
		Console::OnRequestCls.connect(&Console_OnRequestCls);
		Console::Init();
		ScriptModule::Load();
	}

	imeWindow = new VWD::ImeWindowForCegui();
	IME::Win32ImeSensor::getInstancePtr()->SetImeWindow(imeWindow);
}

void VWD::UIEnv::Shutdown()
{	
	IME::Win32ImeSensor::getInstancePtr()->SetImeWindow(0);
	delete imeWindow;
	CEGUI::OgreRenderer::destroySystem();
	//CEGUI::System::destroy();
}

bool VWD::UIEnv::isUsingSystemCursor() const
{
	return USESYSTEMMOUSECURSOR;
}

HCURSOR VWD::UIEnv::getCurrentSystemCursor() const
{
	return currentCursor;
}